﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Services;
using System.IO;
using System.Diagnostics;
using System.Drawing.Drawing2D;
using System.Drawing;
using Binarizer = com.google.zxing.Binarizer;
using LuminanceSource = com.google.zxing.LuminanceSource;
using com.google.zxing.qrcode;
using com.google.zxing;
using com.google.zxing.common;


namespace WebApplication2
{
    /// <summary>
    /// Summary description for WebService1
    /// </summary>
    [WebService(Namespace = "http://tempuri.org/")]
    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
    [System.ComponentModel.ToolboxItem(false)]
    // To allow this Web Service to be called from script, using ASP.NET AJAX, uncomment the following line. 
    // [System.Web.Script.Services.ScriptService]
    public class WebService1 : System.Web.Services.WebService
    {
        private bool debugging = true;
        static int nf = 1;
        private int left;
        private int top;
        private int right;
        private int bottom;
        private CuitQrAfip cuitData = new CuitQrAfip();

        //static private String logFile = @"C:\Desa\MunQr\03_Server\01_src\wserv.log";
        private String logFile = @"C:\log\wslog.log";

        [WebMethod]
        public string getDate(DateTime fecha)
        {
            String date = fecha.ToString("G");
            return date;
        }

        [WebMethod]
        public string getXmlData(string cuit)
        {
            // busca en la base y retorna con los campos que fueran.
            // EN el futuro se comunicará con otro webserver que le devolverá los datos...
            if (string.IsNullOrEmpty(cuit))
                return string.Empty;


            String filename = "./XMLData1.xml";
            String filePathName = @"C:\Desa\munqr\03_Server\01_src\WebApplication2\" + filename;
            String datos;
            using (var stream = new StreamReader(filePathName))
            {
                datos = stream.ReadToEnd();
            }
            
            return datos;
        }

        /*
         * Este metodo recibe usuario y un string que es la imagen. 
        [WebMethod]
        public string ProcessImage(string usr, string hex)
        {
            
            if (string.IsNullOrEmpty(hex))
                return string.Empty;

            if (string.IsNullOrEmpty(usr))
                usr = "6a75616e";   // juan

            var image = StringHexToByteArray(hex);
            //var imageStr = System.Text.Encoding.UTF8.GetString(image);
            var usrbyte = StringHexToByteArray(usr);
            string username = System.Text.Encoding.UTF8.GetString(usrbyte);

            //getCriticalPoints(image);

            //var username = "juan";
            var dir = @"s:\munqr\";
            var filePhoto = dir + username + nf++ + ".jpg" ;
            

            using (var stream = new FileStream(filePhoto, FileMode.Create))
            {
                using (var writer = new BinaryWriter(stream))
                {
                    writer.Write(image);
                    writer.Close();
                }
            }

            String res = getTextFromImage(filePhoto);
            return res;
        }
         */


        [WebMethod]
        public string ProcessCuitImage(String fileName)
        {

            String dirj = Path.GetDirectoryName(fileName) + "/";

            // para debuggear. Si no trajo directorio se asume que se puso desde la pagina del webserver wsdl
            if (Path.GetDirectoryName(fileName).Equals(""))
            {
                dirj = "c:/desa/munqr/03_Server/01_src/uploaded/";
                fileName = "c:/desa/munqr/03_Server/01_src/uploaded/" + fileName;  
            }
            String ocrResult = "";
            String xmlData = "";
            ocrResult = getTextFromImage(fileName);
            ocrResult = cuitData.getCuitFromText(ocrResult);

            if (ocrResult != null && !ocrResult.Equals(""))
                xmlData = getXmlData(ocrResult);
            if (xmlData != null && !xmlData.Equals("") )
                return ocrResult + "$" + xmlData;
            else
                return "Error: No es posible leer el cuit de la imagen";
        }

        [WebMethod]
        public string ProcessQr(String fileName)
        {
            
            //filename = dirj + @"marcelo_qr.jpg";
            writeLog("Empieza ProcessQr con " + fileName);

            String dirj = Path.GetDirectoryName(fileName) + "/";
            writeLog("path es : " + dirj);
            // para debuggear
            if (Path.GetDirectoryName(fileName).Equals(""))
            {
                dirj = "c:/desa/munqr/03_Server/01_src/uploaded/";
                fileName = "c:/desa/munqr/03_Server/01_src/uploaded/" + fileName;  // para desarrollar...
            }
            String ocrResult="";
            String xmlData="";

            try
            {
                using (Stream BitmapStream = System.IO.File.Open(fileName, System.IO.FileMode.Open, FileAccess.Read))
                {
                    Image img = Image.FromStream(BitmapStream);
                    Bitmap mBitmap;
                    Bitmap picRotated = null;
                    Bitmap picCropped = null;
                    mBitmap = new Bitmap(img);

                    /*
                    // antes que nada, verifico si esta portrait, sino lo roto antes.
                    if (img.Height < img.Width)
                    {
                        mBitmap = rotate(mBitmap, 90);
                        mBitmap.Save(dirj + @"qrRotado90.jpg");
                    }*/


                    try
                    {
                        LuminanceSource source = new RGBLuminanceSource(mBitmap, mBitmap.Width, mBitmap.Height);
                        var binarizer = new HybridBinarizer(source);
                        var binBitmap = new BinaryBitmap(binarizer);
                        QRCodeReader reader = new QRCodeReader();

                        Result result = (Result)reader.decode(binBitmap);
                        float anglex;
                        bool success;
                        int vez = 1;
                        while (vez <= 3)
                        {
                            success = cuitData.setCuitPosition(result.ResultPoints, mBitmap.Width, mBitmap.Height, vez);
                            if (success)
                            {
                                left = cuitData.left;
                                right = cuitData.right;
                                top = cuitData.top;
                                bottom = cuitData.bottom;
                                anglex = cuitData.anglex;
                                // la rotacion es la misma, no es necesaria la 2da vez.
                                if (vez == 1)
                                {
                                    picRotated = rotate(mBitmap, cuitData.anglex);
                                    if (debugging)
                                    {
                                        writeLog("Guardando Rotado ");
                                        picRotated.Save(dirj + @"qrRotado.jpg");
                                    }
                                }

                                if (picRotated != null)
                                {
                                    picCropped = Crop(picRotated, right - left, top - bottom, left, bottom);
                                    String fileCrop = dirj + @"qrCropped" + vez + @".jpg";
                                    picCropped.Save(fileCrop);
                                    picCropped.Dispose();
                                    ocrResult = getTextFromImage(fileCrop);
                                    ocrResult = cuitData.getCuitFromText(ocrResult);
                                    xmlData = getXmlData(ocrResult);
                                    if (ocrResult != null && !ocrResult.Equals("") && xmlData != null && !xmlData.Equals(""))
                                        vez = 44; // termine.
                                }
                                // ahora lo limpio y controlo que sea un cuit.
                            }
                            vez++;
                        }
                    }
                    catch (Exception ex)
                    {
                        writeLog("Excepcion 2 con ex = " + ex.Message);
                        ocrResult = null;
                    }
                    finally
                    {
                        // liberar resources. Aunque el gc lo va a liberar, de esta forma se libera enseguida.
                        if (BitmapStream != null) BitmapStream.Dispose();  // se usó en un "using", pero x las dudas... 
                        if (img != null) img.Dispose();
                        if (mBitmap != null) mBitmap.Dispose();
                        if (picRotated != null) picRotated.Dispose();
                    }
                }
            }
            catch (Exception ex)
            {
                writeLog("Excepcion 1 con ex = " + ex.Message);
            }
            if (ocrResult != null && !ocrResult.Equals("") && xmlData != null && !xmlData.Equals(""))
                return ocrResult + "$" + xmlData;
            else
                return "Error: No es posible leer el cuit de la imagen";
        }

        // se usa para ver que hay en el dibujo en un pixel determinado.
        [WebMethod]
        public void PintarQr(String fileName, int row, int col)
        {

            //filename = dirj + @"marcelo_qr.jpg";
            writeLog("Empieza PintarQr con " + fileName);
            String dirj = Path.GetDirectoryName(fileName) + "/";
            writeLog("path es : " + dirj);
            // para debuggear
            if (Path.GetDirectoryName(fileName).Equals(""))
            {
                dirj = "c:/desa/munqr/03_Server/01_src/uploaded/";
                fileName = "c:/desa/munqr/03_Server/01_src/uploaded/" + fileName;  // para desarrollar...
            }

            Bitmap bmp = (Bitmap)Image.FromFile(fileName);
            //bmp = zkUtilsDraw.changeColorRow(bmp, 50, Color.Red.R, Color.Red.G, Color.Red.B);
            //bmp.Save("c:/tmp/24/marcelo_qrRow50.jpg");
            //bmp = zkUtilsDraw.changeColorColumn(bmp, 20, Color.Red.R, Color.Red.G, Color.Red.B);
            //bmp.Save("c:/tmp/24/marcelo_qrCol20.jpg");
            bmp = zkUtilsDraw.changeColorRowCol(bmp, row, col, Color.Red.R, Color.Red.G, Color.Red.B);
            bmp.Save("c:/tmp/24/"+Path.GetFileName(fileName)+"R"+row+"C"+col+".jpg");

        }


        private String getTextFromImage(String filePhoto)
        {
            var p = new Process();

            p.StartInfo.FileName = @"C:\Desa\munqr\Tesseract.exe";
            String fileResult = Path.ChangeExtension(filePhoto, ".txt");

            // para tesseract se manda sin extension, se lo pone él.
            String dirPath = Path.GetDirectoryName(filePhoto);
            String fileRes = dirPath + "\\" + Path.GetFileNameWithoutExtension(fileResult);
            p.StartInfo.Arguments = filePhoto + " " + fileRes;
            p.StartInfo.UseShellExecute = false;
            p.StartInfo.RedirectStandardOutput = true;
            p.Start();

            // lee de l output de la pantalla...
            string output = p.StandardOutput.ReadToEnd();
            p.WaitForExit();

            string ocrResult;
            using (var stream = new StreamReader(fileResult))
            {
                ocrResult = stream.ReadToEnd();
            }
            return ocrResult;
        }

        public static byte[] StringHexToByteArray(string hex)
        {
            var aux = Enumerable.Range(0, 
                
                hex.Length)
                             .Where(x => x % 2 == 0)
                             .Select(x => Convert.ToByte(hex.Substring(x, 2), 16))
                             .ToArray();
            return aux;

        }

       
        /// <summary>
        /// method to rotate an image either clockwise or counter-clockwise
        /// </summary>
        /// <param name="img">the image to be rotated</param>
        /// <param name="rotationAngle">the angle (in degrees).
        /// NOTE: 
        /// Positive values will rotate clockwise
        /// negative values will rotate counter-clockwise
        /// </param>
        /// <returns></returns>
        private Bitmap rotate(Bitmap bmp, float rotationAngle)
        {
            //create an empty Bitmap image
            //Bitmap bmp = new Bitmap(img.Width, img.Height);
            //rotationAngle = 1.57f;

            //turn the Bitmap into a Graphics object
            Graphics gfx = Graphics.FromImage(bmp);


            //now we set the rotation point to the center of our image
            gfx.TranslateTransform((float)bmp.Width / 2, (float)bmp.Height / 2);

            //now rotate the image
            gfx.RotateTransform(rotationAngle);

            gfx.TranslateTransform(-(float)bmp.Width / 2, -(float)bmp.Height / 2);

            //set the InterpolationMode to HighQualityBicubic so to ensure a high
            //quality image once it is transformed to the specified size
            gfx.InterpolationMode = InterpolationMode.HighQualityBicubic;

            //now draw our new image onto the graphics object
            gfx.DrawImage(bmp, new Point(0, 0));

            //dispose of our Graphics object
            gfx.Dispose();

            //return the image
            return bmp;
        }
        private Bitmap Crop(Image image, int width, int height, int x, int y)
        {
            try
            {
                //Image image = Image.FromFile(img);
                Bitmap bmp = new Bitmap(width, height, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
                bmp.SetResolution(image.HorizontalResolution, image.VerticalResolution);
                //bmp.SetResolution(80, 60);

                Graphics gfx = Graphics.FromImage(bmp);
                gfx.SmoothingMode = SmoothingMode.AntiAlias;
                gfx.InterpolationMode = InterpolationMode.HighQualityBicubic;
                gfx.PixelOffsetMode = PixelOffsetMode.HighQuality;
                gfx.DrawImage(image, new Rectangle(0, 0, width, height), x, y, width, height, GraphicsUnit.Pixel);
                // Dispose to free up resources
                //image.Dispose();
                //bmp.Dispose();
                gfx.Dispose();
                return bmp;
            }
            catch (Exception ex)
            {
                writeLog("Excepcion CROP: " + ex.Message);
                return null;
            }
        }

        private void writeLog(String str)
        {
            using (System.IO.StreamWriter file = new System.IO.StreamWriter(logFile, true))
            {
                file.WriteLine(str);
                file.Close();
            }
        }

    }
}
